home *** CD-ROM | disk | FTP | other *** search
/ Whiteline: Alpha / Whiteline Alpha.iso / linux / atari / source / source.lzh / atari-linux-0.01pl3 / ipc / shm.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-06-05  |  17.7 KB  |  729 lines

  1. /*
  2.  * linux/ipc/shm.c
  3.  * Copyright (C) 1992, 1993 Krishna Balasubramanian 
  4.  *         Many improvements/fixes by Bruno Haible.
  5.  * assume user segments start at 0x0
  6.  */
  7.  
  8. #include <linux/errno.h>
  9. #include <asm/segment.h>
  10. #include <linux/sched.h>
  11. #include <linux/ipc.h> 
  12. #include <linux/shm.h>
  13. #include <linux/stat.h>
  14. #include <linux/malloc.h>
  15.  
  16. extern int ipcperms (struct ipc_perm *ipcp, short semflg);
  17. extern unsigned int get_swap_page(void);
  18. static int findkey (key_t key);
  19. static int newseg (key_t key, int shmflg, int size);
  20. static int shm_map (struct shm_desc *shmd, int remap);
  21. static void killseg (int id);
  22.  
  23. static int shm_tot = 0;  /* total number of shared memory pages */
  24. static int shm_rss = 0; /* number of shared memory pages that are in memory */
  25. static int shm_swp = 0; /* number of shared memory pages that are in swap */
  26. static int shm_seq = 0; /* is incremented, for recognizing stale ids */
  27. static int max_shmid = 0; /* every used id is <= max_shmid */
  28. static struct wait_queue *shm_lock = NULL;
  29. static struct shmid_ds *shm_segs[SHMMNI];
  30.  
  31. /* some statistics */
  32. static ulong swap_attempts = 0;
  33. static ulong swap_successes = 0;
  34. static ulong used_segs = 0;
  35.  
  36. void shm_init (void)
  37. {
  38.     int id;
  39.     
  40.            for (id = 0; id < SHMMNI; id++) 
  41.         shm_segs[id] = (struct shmid_ds *) IPC_UNUSED;
  42.     shm_tot = shm_rss = shm_seq = max_shmid = used_segs = 0;
  43.     shm_lock = NULL;
  44.     return;
  45. }
  46.  
  47. static int findkey (key_t key)    
  48. {
  49.     int id;
  50.     struct shmid_ds *shp;
  51.     
  52.     for (id=0; id <= max_shmid; id++) {
  53.         while ((shp = shm_segs[id]) == IPC_NOID) 
  54.             sleep_on (&shm_lock);
  55.         if (shp == IPC_UNUSED)
  56.             continue;
  57.         if (key == shp->shm_perm.key) 
  58.             return id;
  59.     }
  60.     return -1;
  61. }
  62.  
  63. /* 
  64.  * allocate new shmid_ds and pgtable. protected by shm_segs[id] = NOID.
  65.  */
  66. static int newseg (key_t key, int shmflg, int size)
  67. {
  68.     struct shmid_ds *shp;
  69.     int numpages = (size + PAGE_SIZE -1) >> PAGE_SHIFT;
  70.     int id, i;
  71.  
  72.     if (size < SHMMIN)
  73.         return -EINVAL;
  74.     if (shm_tot + numpages >= SHMALL)
  75.         return -ENOSPC;
  76.     for (id=0; id < SHMMNI; id++)
  77.         if (shm_segs[id] == IPC_UNUSED) {
  78.             shm_segs[id] = (struct shmid_ds *) IPC_NOID;
  79.             goto found;
  80.         }
  81.     return -ENOSPC;
  82.  
  83. found:
  84.     shp = (struct shmid_ds *) kmalloc (sizeof (*shp), GFP_KERNEL);
  85.     if (!shp) {
  86.         shm_segs[id] = (struct shmid_ds *) IPC_UNUSED;
  87.         if (shm_lock)
  88.             wake_up (&shm_lock);
  89.         return -ENOMEM;
  90.     }
  91.  
  92.     shp->shm_pages = (ulong *) kmalloc (numpages*sizeof(ulong),GFP_KERNEL);
  93.     if (!shp->shm_pages) {
  94.         shm_segs[id] = (struct shmid_ds *) IPC_UNUSED;
  95.         if (shm_lock)
  96.             wake_up (&shm_lock);
  97.         kfree_s (shp, sizeof (*shp));
  98.         return -ENOMEM;
  99.     }
  100.  
  101.     for (i=0; i< numpages; shp->shm_pages[i++] = 0);
  102.     shm_tot += numpages;
  103.     shp->shm_perm.key = key;
  104.     shp->shm_perm.mode = (shmflg & S_IRWXUGO);
  105.     shp->shm_perm.cuid = shp->shm_perm.uid = current->euid;
  106.     shp->shm_perm.cgid = shp->shm_perm.gid = current->egid;
  107.     shp->shm_perm.seq = shm_seq;
  108.     shp->shm_segsz = size;
  109.     shp->shm_cpid = current->pid;
  110.     shp->attaches = NULL;
  111.     shp->shm_lpid = shp->shm_nattch = 0;
  112.     shp->shm_atime = shp->shm_dtime = 0;
  113.     shp->shm_ctime = CURRENT_TIME;
  114.     shp->shm_npages = numpages;
  115.  
  116.     if (id > max_shmid)
  117.         max_shmid = id;
  118.     shm_segs[id] = shp;
  119.     used_segs++;
  120.     if (shm_lock)
  121.         wake_up (&shm_lock);
  122.     return id + shm_seq*SHMMNI;
  123. }
  124.  
  125. int sys_shmget (key_t key, int size, int shmflg)
  126. {
  127.     struct shmid_ds *shp;
  128.     int id = 0;
  129.     
  130.     if (size < 0 || size > SHMMAX)
  131.         return -EINVAL;
  132.     if (key == IPC_PRIVATE) 
  133.         return newseg(key, shmflg, size);
  134.     if ((id = findkey (key)) == -1) {
  135.         if (!(shmflg & IPC_CREAT))
  136.             return -ENOENT;
  137.         return newseg(key, shmflg, size);
  138.     } 
  139.     if ((shmflg & IPC_CREAT) && (shmflg & IPC_EXCL))
  140.         return -EEXIST;
  141.     shp = shm_segs[id];
  142.     if (shp->shm_perm.mode & SHM_DEST)
  143.         return -EIDRM;
  144.     if (size > shp->shm_segsz)
  145.         return -EINVAL;
  146.     if (ipcperms (&shp->shm_perm, shmflg))
  147.         return -EACCES;
  148.     return shp->shm_perm.seq*SHMMNI + id;
  149. }
  150.  
  151. /* 
  152.  * Only called after testing nattch and SHM_DEST.
  153.  * Here pages, pgtable and shmid_ds are freed.
  154.  */
  155. static void killseg (int id)
  156. {
  157.     struct shmid_ds *shp;
  158.     int i, numpages;
  159.     ulong page;
  160.  
  161.     shp = shm_segs[id];
  162.     if (shp == IPC_NOID || shp == IPC_UNUSED) {
  163.         printk ("shm nono: killseg called on unused seg id=%d\n", id);
  164.         return;
  165.     }
  166.     shp->shm_perm.seq++;     /* for shmat */
  167.     numpages = shp->shm_npages; 
  168.     if ((int)((++shm_seq + 1) * SHMMNI) < 0)
  169.         shm_seq = 0;
  170.     shm_segs[id] = (struct shmid_ds *) IPC_UNUSED;
  171.     used_segs--;
  172.     if (id == max_shmid) 
  173.         while (max_shmid && (shm_segs[--max_shmid] == IPC_UNUSED));
  174.     if (!shp->shm_pages) {
  175.         printk ("shm nono: killseg shp->pages=NULL. id=%d\n", id);
  176.         return;
  177.     }
  178.     for (i=0; i< numpages ; i++) {
  179.         if (!(page = shp->shm_pages[i]))
  180.             continue;
  181.         if (page & 1) {
  182.             free_page (page & PAGE_MASK);
  183.             shm_rss--;
  184.         } else {
  185.             swap_free (page);
  186.             shm_swp--;
  187.         }
  188.     }
  189.     kfree_s (shp->shm_pages, numpages * sizeof (ulong));
  190.     shm_tot -= numpages;
  191.     kfree_s (shp, sizeof (*shp));
  192.     return;
  193. }
  194.  
  195. int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
  196. {
  197.     struct shmid_ds *shp, tbuf;
  198.     struct ipc_perm *ipcp;
  199.     int id, err;
  200.     
  201.     if (cmd < 0 || shmid < 0)
  202.         return -EINVAL;
  203.     if (cmd == IPC_SET) {
  204.         if (!buf)
  205.             return -EFAULT;
  206.         err = verify_area (VERIFY_READ, buf, sizeof (*buf));
  207.         if (err)
  208.             return err;
  209.         memcpy_fromfs (&tbuf, buf, sizeof (*buf));
  210.     }
  211.  
  212.     switch (cmd) { /* replace with proc interface ? */
  213.     case IPC_INFO: 
  214.     {
  215.         struct shminfo shminfo;
  216.         if (!buf)
  217.             return -EFAULT;
  218.         shminfo.shmmni = SHMMNI;
  219.         shminfo.shmmax = SHMMAX;
  220.         shminfo.shmmin = SHMMIN;
  221.         shminfo.shmall = SHMALL;
  222.         shminfo.shmseg = SHMSEG;
  223.         err = verify_area (VERIFY_WRITE, buf, sizeof (struct shminfo));
  224.         if (err)
  225.             return err;
  226.         memcpy_tofs (buf, &shminfo, sizeof(struct shminfo));
  227.         return max_shmid;
  228.     }
  229.     case SHM_INFO: 
  230.     { 
  231.         struct shm_info shm_info;
  232.         if (!buf)
  233.             return -EFAULT;
  234.         err = verify_area (VERIFY_WRITE, buf, sizeof (shm_info));
  235.         if (err)
  236.             return err;
  237.         shm_info.used_ids = used_segs; 
  238.         shm_info.shm_rss = shm_rss;
  239.         shm_info.shm_tot = shm_tot;
  240.         shm_info.shm_swp = shm_swp;
  241.         shm_info.swap_attempts = swap_attempts;
  242.         shm_info.swap_successes = swap_successes;
  243.         memcpy_tofs (buf, &shm_info, sizeof(shm_info));
  244.         return max_shmid;
  245.     }
  246.     case SHM_STAT:
  247.         if (!buf)
  248.             return -EFAULT;
  249.         err = verify_area (VERIFY_WRITE, buf, sizeof (*shp));
  250.         if (err)
  251.             return err;
  252.         if (shmid > max_shmid)
  253.             return -EINVAL;
  254.         shp = shm_segs[shmid];
  255.         if (shp == IPC_UNUSED || shp == IPC_NOID)
  256.             return -EINVAL;
  257.         if (ipcperms (&shp->shm_perm, S_IRUGO))
  258.             return -EACCES;
  259.         id = shmid + shp->shm_perm.seq * SHMMNI; 
  260.         memcpy_tofs (buf, shp, sizeof(*shp));
  261.         return id;
  262.     }
  263.     
  264.     shp = shm_segs[id = shmid % SHMMNI];
  265.     if (shp == IPC_UNUSED || shp == IPC_NOID)
  266.         return -EINVAL;
  267.     ipcp = &shp->shm_perm;
  268.     if (ipcp->seq != shmid / SHMMNI) 
  269.         return -EIDRM;
  270.     
  271.     switch (cmd) {
  272.     case SHM_UNLOCK:
  273.         if (!suser())
  274.             return -EPERM;
  275.         if (!(ipcp->mode & SHM_LOCKED))
  276.             return -EINVAL;
  277.         ipcp->mode &= ~SHM_LOCKED;
  278.         break;
  279.     case SHM_LOCK:
  280. /* Allow superuser to lock segment in memory */
  281. /* Should the pages be faulted in here or leave it to user? */
  282. /* need to determine interaction with current->swappable */
  283.         if (!suser())
  284.             return -EPERM;
  285.         if (ipcp->mode & SHM_LOCKED)
  286.             return -EINVAL;
  287.         ipcp->mode |= SHM_LOCKED;
  288.         break;
  289.     case IPC_STAT:
  290.         if (ipcperms (ipcp, S_IRUGO))
  291.             return -EACCES;
  292.         if (!buf)
  293.             return -EFAULT;
  294.         err = verify_area (VERIFY_WRITE, buf, sizeof (*shp));
  295.         if (err)
  296.             return err;
  297.         memcpy_tofs (buf, shp, sizeof(*shp));
  298.         break;
  299.     case IPC_SET:
  300.         if (suser() || current->euid == shp->shm_perm.uid ||
  301.             current->euid == shp->shm_perm.cuid) {
  302.             ipcp->uid = tbuf.shm_perm.uid;
  303.             ipcp->gid = tbuf.shm_perm.gid;
  304.             ipcp->mode = (ipcp->mode & ~S_IRWXUGO)
  305.                 | (tbuf.shm_perm.mode & S_IRWXUGO);
  306.             shp->shm_ctime = CURRENT_TIME;
  307.             break;
  308.         }
  309.         return -EPERM;
  310.     case IPC_RMID:
  311.         if (suser() || current->euid == shp->shm_perm.uid ||
  312.             current->euid == shp->shm_perm.cuid) {
  313.             shp->shm_perm.mode |= SHM_DEST;
  314.             if (shp->shm_nattch <= 0) 
  315.                 killseg (id);
  316.             break;
  317.         }
  318.         return -EPERM;
  319.     default:
  320.         return -EINVAL;
  321.     }
  322.     return 0;
  323. }
  324.  
  325. /*
  326.  * check range is unmapped, ensure page tables exist
  327.  * mark page table entries with shm_sgn.
  328.  * if remap != 0 the range is remapped.
  329.  */
  330. static int shm_map (struct shm_desc *shmd, int remap)
  331. {
  332.     unsigned long invalid = 0;
  333.     unsigned long *page_table;
  334.     unsigned long tmp, shm_sgn;
  335.     unsigned long page_dir = shmd->task->tss.cr3;
  336.     
  337.     /* check that the range is unmapped and has page_tables */
  338.     for (tmp = shmd->start; tmp < shmd->end; tmp += PAGE_SIZE) { 
  339.         page_table = PAGE_DIR_OFFSET(page_dir,tmp);
  340.         if (*page_table & PAGE_PRESENT) {
  341.             page_table = (ulong *) (PAGE_MASK & *page_table);
  342.             page_table += ((tmp >> PAGE_SHIFT) & (PTRS_PER_PAGE-1));
  343.             if (*page_table) {
  344.                 if (!remap)
  345.                     return -EINVAL;
  346.                 if (*page_table & PAGE_PRESENT) {
  347.                     --current->rss;
  348.                     free_page (*page_table & PAGE_MASK);
  349.                 }
  350.                 else
  351.                     swap_free (*page_table);
  352.                 invalid++;
  353.             }
  354.             continue;
  355.         }  
  356.           {
  357.         unsigned long new_pt;
  358.         if(!(new_pt = get_free_page(GFP_KERNEL)))    /* clearing needed?  SRB. */
  359.             return -ENOMEM;
  360.         *page_table = new_pt | PAGE_TABLE;
  361.         tmp |= ((PAGE_SIZE << 10) - PAGE_SIZE);
  362.     }}
  363.     if (invalid)
  364.         invalidate();
  365.  
  366.     /* map page range */
  367.     shm_sgn = shmd->shm_sgn;
  368.     for (tmp = shmd->start; tmp < shmd->end; tmp += PAGE_SIZE, 
  369.          shm_sgn += (1 << SHM_IDX_SHIFT)) { 
  370.         page_table = PAGE_DIR_OFFSET(page_dir,tmp);
  371.         page_table = (ulong *) (PAGE_MASK & *page_table);
  372.         page_table += (tmp >> PAGE_SHIFT) & (PTRS_PER_PAGE-1);
  373.         *page_table = shm_sgn;
  374.     }
  375.     return 0;
  376. }
  377.  
  378. /* 
  379.  * Fix shmaddr, allocate descriptor, map shm, add attach descriptor to lists.
  380.  * raddr is needed to return addresses above 2Gig.
  381.  * Specific attaches are allowed over the executable....
  382.  */
  383. int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr)
  384. {
  385.     struct shmid_ds *shp;
  386.     struct shm_desc *shmd;
  387.     int err;
  388.     unsigned int id;
  389.     unsigned long addr;
  390.     
  391.     if (shmid < 0)
  392.         return -EINVAL;
  393.  
  394.     shp = shm_segs[id = shmid % SHMMNI];
  395.     if (shp == IPC_UNUSED || shp == IPC_NOID)
  396.         return -EINVAL;
  397.  
  398.     if (!(addr = (ulong) shmaddr)) {
  399.         if (shmflg & SHM_REMAP)
  400.             return -EINVAL;
  401.         /* set addr below  all current unspecified attaches */
  402.         addr = SHM_RANGE_END; 
  403.         for (shmd = current->shm; shmd; shmd = shmd->task_next) {
  404.             if (shmd->start < SHM_RANGE_START)
  405.                 continue;
  406.             if (addr >= shmd->start)
  407.                 addr = shmd->start;
  408.         }
  409.         addr = (addr - shp->shm_segsz) & PAGE_MASK;
  410.     } else if (addr & (SHMLBA-1)) {
  411.         if (shmflg & SHM_RND) 
  412.             addr &= ~(SHMLBA-1);       /* round down */
  413.         else
  414.             return -EINVAL;
  415.     }
  416.     if ((addr > current->start_stack - 16384 - PAGE_SIZE*shp->shm_npages))
  417.         return -EINVAL;
  418.     if (shmflg & SHM_REMAP)
  419.         for (shmd = current->shm; shmd; shmd = shmd->task_next) {
  420.             if (addr >= shmd->start && addr < shmd->end)
  421.                 return -EINVAL;
  422.             if (addr + shp->shm_segsz >= shmd->start && 
  423.                 addr + shp->shm_segsz < shmd->end)
  424.                 return -EINVAL;
  425.         }
  426.  
  427.     if (ipcperms(&shp->shm_perm, shmflg & SHM_RDONLY ? S_IRUGO : S_IRUGO|S_IWUGO))
  428.         return -EACCES;
  429.     if (shp->shm_perm.seq != shmid / SHMMNI) 
  430.         return -EIDRM;
  431.  
  432.     shmd = (struct shm_desc *) kmalloc (sizeof(*shmd), GFP_KERNEL);
  433.     if (!shmd)
  434.         return -ENOMEM;
  435.     if ((shp != shm_segs[id]) || (shp->shm_perm.seq != shmid / SHMMNI)) {
  436.         kfree_s (shmd, sizeof (*shmd));
  437.         return -EIDRM;
  438.     }
  439.     shmd->shm_sgn = (SHM_SWP_TYPE << 1) | (id << SHM_ID_SHIFT) |
  440.         (shmflg & SHM_RDONLY ? SHM_READ_ONLY : 0);
  441.            shmd->start = addr;
  442.     shmd->end = addr + shp->shm_npages * PAGE_SIZE;
  443.     shmd->task = current;
  444.  
  445.     shp->shm_nattch++;            /* prevent destruction */
  446.     if (addr < current->end_data) {
  447.         iput (current->executable);
  448.         current->executable = NULL;
  449. /*        current->end_data = current->end_code = 0; */
  450.     }
  451.  
  452.     if ((err = shm_map (shmd, shmflg & SHM_REMAP))) {
  453.         if (--shp->shm_nattch <= 0 && shp->shm_perm.mode & SHM_DEST)
  454.             killseg(id);
  455.         kfree_s (shmd, sizeof (*shmd));
  456.         return err;
  457.     }
  458.         
  459.     shmd->task_next = current->shm;
  460.     current->shm = shmd;
  461.     shmd->seg_next = shp->attaches;
  462.     shp->attaches = shmd;
  463.     shp->shm_lpid = current->pid;
  464.     shp->shm_atime = CURRENT_TIME;
  465.     put_fs_long (addr, raddr);
  466.     return 0;
  467. }
  468.  
  469. /*
  470.  * remove the first attach descriptor from the list *shmdp.
  471.  * free memory for segment if it is marked destroyed.
  472.  * The descriptor is detached before the sleep in unmap_page_range.
  473.  */
  474. static void detach (struct shm_desc **shmdp)
  475. {
  476.      struct shm_desc *shmd = *shmdp; 
  477.       struct shmid_ds *shp;
  478.       int id;
  479.     
  480.     id = (shmd->shm_sgn >> SHM_ID_SHIFT) & SHM_ID_MASK;
  481.       shp = shm_segs[id];
  482.      *shmdp = shmd->task_next;
  483.      for (shmdp = &shp->attaches; *shmdp; shmdp = &(*shmdp)->seg_next)
  484.         if (*shmdp == shmd) {
  485.             *shmdp = shmd->seg_next; 
  486.             goto found; 
  487.         }
  488.      printk("detach: shm segment (id=%d) attach list inconsistent\n",id);
  489.     
  490.  found:
  491.     unmap_page_range (shmd->start, shp->shm_segsz); /* sleeps */
  492.     kfree_s (shmd, sizeof (*shmd));
  493.       shp->shm_lpid = current->pid;
  494.     shp->shm_dtime = CURRENT_TIME;
  495.     if (--shp->shm_nattch <= 0 && shp->shm_perm.mode & SHM_DEST)
  496.         killseg (id); /* sleeps */
  497.       return;
  498. }
  499.  
  500. /*
  501.  * detach and kill segment if marked destroyed.
  502.  * The work is done in detach.
  503.  */
  504. int sys_shmdt (char *shmaddr)
  505. {
  506.     struct shm_desc *shmd, **shmdp;    
  507.     
  508.     for (shmdp = ¤t->shm; (shmd = *shmdp); shmdp=&shmd->task_next) { 
  509.         if (shmd->start == (ulong) shmaddr) {
  510.             detach (shmdp);
  511.             return 0;
  512.         }
  513.     }
  514.     return -EINVAL;
  515. }
  516.  
  517. /* 
  518.  * detach all attached segments. 
  519.  */
  520. void shm_exit (void)
  521. {
  522.      while (current->shm) 
  523.         detach(¤t->shm);
  524.       return;
  525. }
  526.  
  527. /* 
  528.  * copy the parent shm descriptors and update nattch
  529.  * parent is stuck in fork so an attach on each segment is assured.
  530.  * copy_page_tables does the mapping.
  531.  */
  532. int shm_fork (struct task_struct *p1, struct task_struct *p2)
  533. {
  534.     struct shm_desc *shmd, *new_desc = NULL, *tmp;
  535.     struct shmid_ds *shp;
  536.     int id;
  537.  
  538.         if (!p1->shm)
  539.         return 0;
  540.     for (shmd = p1->shm; shmd; shmd = shmd->task_next) {
  541.         tmp = (struct shm_desc *) kmalloc(sizeof(*tmp), GFP_KERNEL);
  542.         if (!tmp) {
  543.             while (new_desc) { 
  544.                 tmp = new_desc->task_next; 
  545.                 kfree_s (new_desc, sizeof (*new_desc)); 
  546.                 new_desc = tmp; 
  547.             }
  548.             free_page_tables (p2);
  549.             return -ENOMEM;
  550.         }
  551.         *tmp = *shmd;
  552.         tmp->task = p2;
  553.         tmp->task_next = new_desc;
  554.         new_desc = tmp;
  555.     }
  556.     p2->shm = new_desc;
  557.     for (shmd = new_desc; shmd; shmd = shmd->task_next) {
  558.         id = (shmd->shm_sgn >> SHM_ID_SHIFT) & SHM_ID_MASK;
  559.         shp = shm_segs[id];
  560.         if (shp == IPC_UNUSED) {
  561.             printk("shm_fork: unused id=%d PANIC\n", id);
  562.             return -ENOMEM;
  563.         }
  564.         shmd->seg_next = shp->attaches;
  565.         shp->attaches = shmd;
  566.         shp->shm_nattch++;
  567.         shp->shm_atime = CURRENT_TIME;
  568.         shp->shm_lpid = current->pid;
  569.     }
  570.     return 0;
  571. }
  572.  
  573. /*
  574.  * page not present ... go through shm_pages .. called from swap_in()
  575.  */
  576. void shm_no_page (unsigned long *ptent)
  577. {
  578.     unsigned long page;
  579.     unsigned long code = *ptent;
  580.     struct shmid_ds *shp;
  581.     unsigned int id, idx;
  582.  
  583.     id = (code >> SHM_ID_SHIFT) & SHM_ID_MASK;
  584.     if (id > max_shmid) {
  585.         printk ("shm_no_page: id=%d too big. proc mem corruptedn", id);
  586.         return;
  587.     }
  588.     shp = shm_segs[id];
  589.     if (shp == IPC_UNUSED || shp == IPC_NOID) {
  590.         printk ("shm_no_page: id=%d invalid. Race.\n", id);
  591.         return;
  592.     }
  593.     idx = (code >> SHM_IDX_SHIFT) & SHM_IDX_MASK;
  594.     if (idx >= shp->shm_npages) {
  595.         printk ("shm_no_page : too large page index. id=%d\n", id);
  596.         return;
  597.     }
  598.  
  599.     if (!(shp->shm_pages[idx] & PAGE_PRESENT)) {
  600.         if(!(page = get_free_page(GFP_KERNEL))) {
  601.             oom(current);
  602.             *ptent = BAD_PAGE | PAGE_ACCESSED | 7;
  603.             return;
  604.         }
  605.         if (shp->shm_pages[idx] & PAGE_PRESENT) {
  606.             free_page (page);
  607.             goto done;
  608.         }
  609.         if (shp->shm_pages[idx]) {
  610.             read_swap_page (shp->shm_pages[idx], (char *) page);
  611.             if (shp->shm_pages[idx] & PAGE_PRESENT)  {
  612.                 free_page (page);
  613.                 goto done;
  614.             }
  615.             swap_free (shp->shm_pages[idx]);
  616.             shm_swp--;
  617.         }
  618.         shm_rss++;
  619.         shp->shm_pages[idx] = page | (PAGE_SHARED | PAGE_DIRTY);
  620.     } else 
  621.         --current->maj_flt;  /* was incremented in do_no_page */
  622.  
  623. done:
  624.     current->min_flt++;
  625.     page = shp->shm_pages[idx];
  626.     if (code & SHM_READ_ONLY)           /* write-protect */
  627.         page &= ~2;
  628.     mem_map[MAP_NR(page)]++;
  629.     *ptent = page;
  630.     return;
  631. }
  632.  
  633. /*
  634.  * Goes through counter = (shm_rss << prio) present shm pages. 
  635.  */
  636. static unsigned long swap_id = 0; /* currently being swapped */
  637. static unsigned long swap_idx = 0; /* next to swap */
  638.  
  639. int shm_swap (int prio)
  640. {
  641.     unsigned long page;
  642.     struct shmid_ds *shp;
  643.     struct shm_desc *shmd;
  644.     unsigned int swap_nr;
  645.     unsigned long id, idx, invalid = 0;
  646.     int counter;
  647.  
  648.     counter = shm_rss >> prio;
  649.     if (!counter || !(swap_nr = get_swap_page()))
  650.         return 0;
  651.  
  652.  check_id:
  653.     shp = shm_segs[swap_id];
  654.     if (shp == IPC_UNUSED || shp == IPC_NOID || shp->shm_perm.mode & SHM_LOCKED ) {
  655.         swap_idx = 0; 
  656.         if (++swap_id > max_shmid)
  657.             swap_id = 0;
  658.         goto check_id;
  659.     }
  660.     id = swap_id;
  661.  
  662.  check_table:
  663.     idx = swap_idx++; 
  664.     if (idx  >= shp->shm_npages) { 
  665.         swap_idx = 0;
  666.         if (++swap_id > max_shmid)
  667.             swap_id = 0;
  668.         goto check_id;
  669.     }
  670.  
  671.     page = shp->shm_pages[idx];
  672.     if (!(page & PAGE_PRESENT))
  673.         goto check_table;
  674.     swap_attempts++;
  675.  
  676.     if (--counter < 0) { /* failed */
  677.         if (invalid)
  678.             invalidate();
  679.         swap_free (swap_nr);
  680.         return 0;
  681.     }
  682.     for (shmd = shp->attaches; shmd; shmd = shmd->seg_next) {
  683.         unsigned long tmp, *pte;
  684.         if ((shmd->shm_sgn >> SHM_ID_SHIFT & SHM_ID_MASK) != id) {
  685.             printk ("shm_swap: id=%ld does not match shmd\n", id);
  686.             continue;
  687.         }
  688.         tmp = shmd->start + (idx << PAGE_SHIFT);
  689.         if (tmp >= shmd->end) {
  690.             printk ("shm_swap: too large idx=%ld id=%ld PANIC\n",idx, id);
  691.             continue;
  692.         }
  693.         pte = PAGE_DIR_OFFSET(shmd->task->tss.cr3,tmp);
  694.         if (!(*pte & 1)) { 
  695.             printk("shm_swap: bad pgtbl! id=%ld start=%lx idx=%ld\n", 
  696.                     id, shmd->start, idx);
  697.             *pte = 0;
  698.             continue;
  699.         } 
  700.         pte = (ulong *) (PAGE_MASK & *pte);
  701.         pte += ((tmp >> PAGE_SHIFT) & (PTRS_PER_PAGE-1));
  702.         tmp = *pte;
  703.         if (!(tmp & PAGE_PRESENT))
  704.             continue;
  705.         if (tmp & PAGE_ACCESSED) {
  706.             *pte &= ~PAGE_ACCESSED;
  707.             continue;  
  708.         }
  709.         tmp = shmd->shm_sgn | idx << SHM_IDX_SHIFT;
  710.         *pte = tmp;
  711.         mem_map[MAP_NR(page)]--;
  712.         shmd->task->rss--;
  713.         invalid++;
  714.     }
  715.  
  716.     if (mem_map[MAP_NR(page)] != 1) 
  717.         goto check_table;
  718.     page &= PAGE_MASK;
  719.     shp->shm_pages[idx] = swap_nr;
  720.     if (invalid)
  721.         invalidate();
  722.     write_swap_page (swap_nr, (char *) page);
  723.     free_page (page);
  724.     swap_successes++;
  725.     shm_swp++;
  726.     shm_rss--;
  727.     return 1;
  728. }
  729.